﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

namespace Narwhunderful.Aphelia.Framework.Net
{

    internal abstract class NarsockCollection : Dictionary<string, NarsockClient>
    {

        NarsockServer _server;

        public new NarsockClient this[string id]
        {
            get
            {
                return base[id];
            }
            protected set
            {
                if (!base.ContainsKey(id)) this.Add(id, value);
                else base[id] = value;
            }
        }

        public NarsockCollection()
            : this(null)
        {
        }

        public NarsockCollection(NarsockServer server)
        {
            _server = server;
        }

        void AddHooks(NarsockClient client)
        {
            client.DataArrival += new EventHandler<NarsockDataArrivalEventArgs>(_server.OnClientDataArrival);
            client.SendProgress += new EventHandler<NarsockSendEventArgs>(_server.OnClientSendProgress);
            client.SendComplete += new EventHandler<NarsockSendEventArgs>(_server.OnClientSendComplete);
            client.StateChanged += new EventHandler<NarsockStateChangedEventArgs>(_server.OnClientStateChanged);
            client.ExceptionReceived += new EventHandler<NarsockExceptionEventArgs>(_server.OnClientExceptionReceived);
        }

        void RemoveHooks(NarsockClient client)
        {
            client.DataArrival -= new EventHandler<NarsockDataArrivalEventArgs>(_server.OnClientDataArrival);
            client.SendProgress -= new EventHandler<NarsockSendEventArgs>(_server.OnClientSendProgress);
            client.SendComplete -= new EventHandler<NarsockSendEventArgs>(_server.OnClientSendComplete);
            client.StateChanged -= new EventHandler<NarsockStateChangedEventArgs>(_server.OnClientStateChanged);
            client.ExceptionReceived -= new EventHandler<NarsockExceptionEventArgs>(_server.OnClientExceptionReceived);
        }

        protected virtual string GenerateID()
        {
            return Guid.NewGuid().ToString();
        }

        public string Accept(Socket socket)
        {
            NarsockClient client = new NarsockClient();
            client.Accept(socket);
            string id = Add(client);
            return id;
        }

        public string Add(NarsockClient client)
        {
            string id = GenerateID();
            client.ID = id;
            base.Add(id, client);
            AddHooks(client);
            return id;
        }

        public new void Clear()
        {
            foreach (NarsockClient c in base.Values)
            {
                RemoveHooks(c);
                c.Close();
            }
            base.Clear();
        }

        public void Remove(NarsockClient client)
        {
            Remove(Find(client));
        }

        public new void Remove(string id)
        {
            if (base.ContainsKey(id))
            {
                RemoveHooks(base[id]);
                base.Remove(id);
            }
        }

        private string Find(NarsockClient client)
        {
            foreach (string id in base.Keys)
            {
                if (object.ReferenceEquals(this[id], client)) return id;
            }
            return null;
        }

    }


}
